package com.scfire.pay

import grails.converters.JSON

import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.concurrent.ArrayBlockingQueue

import net.sf.json.JSONObject

import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory

import com.scfire.alipay.AlipayNotify
import com.scfire.baseInfo.Gson
import com.scfire.message.InterfaceMesage
import com.scfire.project.Donate
import com.scfire.project.Project
import com.scfire.project.SubProject
import com.scfire.security.Authority
import com.scfire.security.Member
import com.scfire.security.MemberAuthority
import com.scfire.util.SIGN
import com.scfire.weixin.WeiXinConstants
import com.scfire.weixin.WeiXinUtil

class PayController {

	def Log LOG = LogFactory.getLog(PayController.class)
	def deviceInfoService
	def weiXinService
	def springSecurityService
	def alipayService
	def SystemMessageService
	def feedBackService	
	def payService

	
	
	private int queueSize = 1000;
    private ArrayBlockingQueue<Map<String,Object>> queue = new ArrayBlockingQueue<Map<String,Object>>(queueSize);
	/**
	 * 付款demo
	 * @return
	 */
	def index() {
		def url = "http://www.51webdata.com/scfire/pay/index"
		Map map = weiXinService.jsapiTicketSign(url)
		def noncestr = map.get("noncestr")
		def jsapi_ticket = map.get("jsapi_ticket")
		def timestamp = map.get("timestamp")
		def sign = map.get("sign")

		render (view : "index" , model : [appid : WeiXinConstants.appid , timestamp : timestamp , nonceStr : noncestr , signature : sign])
	}

	/**
	 * 发起支付请求
	 * @param donate price
	 * @return null
	 *
	 * **/
	def pay(){
		def format = request.getHeader("format")
		def userAgent = request.getHeader("User-Agent")
		def str = deviceInfoService.getDeviceInfo(userAgent)

		def user = (Member)springSecurityService.getCurrentUser()

		//支付项目
		String projectid = params.projectid
		String subprojectid = params.subprojectid
		
		//直接捐款 非一起捐 设置subprojectid=-1
		if(subprojectid==null) subprojectid="-1"
		//支付金额
		String donateprice = params.donateprice
		
		//过滤金额000.***
		String newStr = donateprice.replaceFirst("^0*", "");
		if(newStr.startsWith(".")){
			newStr="0"+newStr
		}
		 donateprice=newStr;

		def noncestr = null
		def jsapi_ticket = null
		def timestamp = null
		def sign = null

		Project project = null

		try{
			project = Project.findById(Long.valueOf(projectid))
			if(project==null){
				notFound()
				return
			}
			Map map = weiXinService.jsapiTicketSign(WeiXinConstants.pay_url)
			noncestr = map.get("noncestr")
			jsapi_ticket = map.get("jsapi_ticket")
			timestamp = map.get("timestamp")
			sign = map.get("sign")
		}catch(Exception e){
			LOG.error("Pay project catch exception. "+e.getMessage())
			notFound()
			return
		}

		withFormat {
			html {
				if("pc".equals(str)){
					render view:"paymb" , model:[project:project,donateprice:donateprice,appid:WeiXinConstants.appid,timestamp:timestamp,nonceStr:noncestr,signature:sign , user : user,subprojectid:subprojectid]
				}
				if("mobile".equals(str)){
					render view:"paymb" , model:[project:project,donateprice:donateprice,appid:WeiXinConstants.appid,timestamp:timestamp,nonceStr:noncestr,signature:sign , user : user,subprojectid:subprojectid]
				}
			}
			json {

			}
		}

	}
	/**
	 * 自动识别是否为微信浏览器，决定是否提交支付宝支付
	 */
	def alipayExplain(){

		def total_fee = params.total_fee
		def projectid = params.projectid
		def memberid = params.memberid
		def checked = params.checked
		def donate_fee = params.donate_fee
		def operate_fee = params.operate_fee
		def subprojectid = params.subprojectid

		render view : "alipayExplain" , model : ["total_fee" : total_fee ,
			"projectid" : projectid ,
			"memberid" : memberid ,
			"checked" : checked ,
			"donate_fee" : donate_fee ,
			"operate_fee" : operate_fee,
			"subprojectid" :subprojectid
		]
	}
	/**
	 * 捐赠支付
	 * @param donate price
	 * @return null
	 *
	 * **/
	def order(){
		def format = request.getHeader("format")
		def userAgent = request.getHeader("User-Agent")
		def str = deviceInfoService.getDeviceInfo(userAgent)
		//获取用户基本信息
		def user = springSecurityService.getCurrentUser()
		def roles = springSecurityService.getAuthentication()?.authorities
		//捐赠者
		Member member = (Member)user

		def body = params.body
		def detail = params.detail
		//捐赠项目
		def projectid = params.projectid
		//是否有捐赠金额
		def checked = params.checked
		def donate_fee = params.donate_fee
		def operate_fee = params.operate_fee
		def subprojectid = params.subprojectid
		//微信支付成功后，返回的自定义参数
		//donateNoNew判断donate是否存入
		long timestap = System.currentTimeMillis()/1000
		String donateNoNew = projectid+""+member.id+""+timestap
		
//		String attach = projectid +"#"+member.id+"#"+checked+"#"+donate_fee+"#"+operate_fee+"#"+subprojectid
//		String attach =     "{\"projectid\":\""+projectid+"\",\"memberid\":\""+member.id+"\","+
//		"\"checked\":\""+checked+"\",\"donate_fee\":\""+donate_fee+"\","+
//		"\"operate_fee\":\""+operate_fee+"\",\"subprojectid\":\""+subprojectid+"\",\"donateNoNew\":\""+donateNoNew+"\"}";
		
		//json  attach 最大127个字符，增加其他字段需要判断是否存在某种情况会超出127字符
		String attach =     "{\"p\":\""+projectid+"\",\"m\":\""+member.id+"\","+
		"\"c\":\""+checked+"\",\"df\":\""+donate_fee+"\","+
		"\"of\":\""+operate_fee+"\",\"s\":\""+subprojectid+"\",\"dn\":\""+donateNoNew+"\"}";

		//捐赠支付金额
		int total_fee = 0
		try{
			float temp = Float.valueOf(params.total_fee)
			total_fee = (int)(temp * 1000)
			total_fee = ((int)total_fee)%10 >5 ? total_fee/10 +1:total_fee/10

		}catch(Exception e){
			LOG.error("donate price cast to float catch exception. "+e.getMessage())
		}

		def openid = member.openid

		Map map = new HashMap();

		//真实上线时，将下面接口开放，现在捐赠将绕过支付接口。！！！！！！！
		map = weiXinService.getOrder(body,detail,total_fee,openid,attach)
		map.put("donateNoNew", donateNoNew)
		println "支付成功返回参数"
		println map
		println "结束"
		/*try{
		 Project project = Project.findById(projectid)
		 if (project == null) {
		 notFound()
		 return
		 }
		 //捐赠信息
		 Donate donate = new Donate()
		 donate.donateNo = UUID.randomUUID()
		 donate.money = total_fee /100.0
		 donate.date = new Date()
		 //donate.status = true
		 donate.member = member
		 donate.project = project
		 donate.save flush:true
		 //donate.insert(failOnError: true)
		 //这里有明显的计算问题，平台管理费并不知道有没有包含在totalfee里面
		 project.rest -= donate.money;
		 project.progress = 100-(project.rest/project.amount)*100;
		 //将剩余的钱捐入某个永久项目
		 if(project.rest < 0){
		 //TODO
		 project.rest = 0;
		 project.progress = 100;
		 }
		 //捐赠的用户去重
		 Set donateMember = new HashSet<>()
		 donateMember.add(member.id)
		 for(Donate d:project.donates){
		 def m = d.member.id
		 donateMember.add(m)
		 }
		 project.donateNum = donateMember.size();
		 project.save (failOnError: true, flush:true)
		 }catch(Exception e){
		 LOG.error("save donate catch exception. "+e.getMessage());
		 }*/

		//	map.put("result", "sucess");
		render map as JSON
	}

	/**
	 *支付宝发起支付请求
	 */
	def alipayOrder(){
		
		
		def total_fee = params.total_fee
		def projectid = params.projectid
		def memberid = params.memberid
		
		def checked
		
		if(params.checked.toLowerCase().equals("true")){
			checked = true
		}else{
			checked = false
		}
		
		Map<String,String> map = new HashMap<String,String>()

		def donate_fee = params.donate_fee as float
		def operate_fee = params.operate_fee as float
		def subprojectid = params.subprojectid

		if(total_fee){
			render alipayService.pay(total_fee , projectid , memberid , checked , donate_fee , operate_fee,subprojectid)
			return
		}
		render "参数不正确"
		return
	}
	/**
	 * 支付宝付款成功跳转方法
	 */
	def alipayReturn(){

		//支付完成后也跳转到中间页面
		redirect(action: "donateFinish")
		//		//获取支付宝GET过来反馈信息
		//		Map<String,String> param = new HashMap<String,String>()
		//		Map requestParams = request.getParameterMap()
		//		for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
		//			String name = (String) iter.next()
		//			String[] values = (String[]) requestParams.get(name)
		//			String valueStr = ""
		//			for (int i = 0; i < values.length; i++) {
		//				valueStr = (i == values.length - 1) ? valueStr + values[i]
		//						: valueStr + values[i] + ",";
		//			}
		//			//乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
		////			valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8")
		//			param.put(name, valueStr)
		//		}
		//
		//		//获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
		//		//商户订单号
		//
		//		String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8")
		//
		//		//支付宝交易号
		//
		//		String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8")
		//
		//		//交易状态
		//		String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8")
		//
		//		//获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
		//
		//		//计算得出通知验证结果
		//		boolean verify_result = AlipayNotify.verify(param)
		//
		//		if(verify_result){//验证成功
		//			//////////////////////////////////////////////////////////////////////////////////////////
		//			//请在这里加上商户的业务逻辑程序代码
		//
		//			//——请根据您的业务逻辑来编写程序（以下代码仅作参考）——
		//			if(trade_status.equals("TRADE_FINISHED") || trade_status.equals("TRADE_SUCCESS")){
		//				//判断该笔订单是否在商户网站中已经做过处理
		//					//如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
		//					//如果有做过处理，不执行商户的业务程序
		//			}
		//			//该页面可做页面美工编辑
		//			render "验证成功"
		//			//——请根据您的业务逻辑来编写程序（以上代码仅作参考）——
		//
		//			//////////////////////////////////////////////////////////////////////////////////////////
		//		}else{
		//			//该页面可做页面美工编辑
		//			render "验证失败"
		//		}
		//		render param
	}
	
	/**
	 * 支付宝回调函数  权限放开
	 */
	/*def alipayNotify(){
		println "支付宝回调.."
		String donateurl = "";
		Map<String,String> param = new HashMap<String,String>()
		Map requestParams = request.getParameterMap()
		for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
			String name = (String) iter.next()
			String[] values = (String[]) requestParams.get(name);
			String valueStr = ""
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == values.length - 1) ? valueStr + values[i]
						: valueStr + values[i] + ","
			}
			//乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
			//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
			param.put(name, valueStr)
			//			println name+":"+valueStr
		}

		//获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
		//商户订单号
		String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
		//支付宝交易号
		String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
		//交易状态
		String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");

		println "交易状态："+trade_status

		String memberid = new String(request.getParameter("memberid").getBytes("ISO-8859-1"),"UTF-8");
		String projectid = new String(request.getParameter("projectid").getBytes("ISO-8859-1"),"UTF-8");
		String subprojectid = new String(request.getParameter("subprojectid").getBytes("ISO-8859-1"),"UTF-8");
		String total_fee = new String(request.getParameter("total_fee").getBytes("ISO-8859-1"),"UTF-8");
		boolean checked;
		String checked_string = new String(request.getParameter("checked").getBytes("ISO-8859-1"),"UTF-8").toLowerCase();
		float donate_fee = Float.parseFloat(new String(request.getParameter("donate_fee").getBytes("ISO-8859-1"),"UTF-8"));
		float operate_fee = Float.parseFloat(new String(request.getParameter("operate_fee").getBytes("ISO-8859-1"),"UTF-8"));

		if(checked_string.equals("true")){
			checked = true
		}else{
			checked = false
		}

		param.remove("memberid")
		param.remove("projectid")
		param.remove("checked")
		param.remove("donate_fee")
		param.remove("operate_fee")
		param.remove("subprojectid")
		//获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//

		if(AlipayNotify.verify(param)){//验证成功
			println "验证成功"

			Project.withTransaction { project_status ->

				Member member = Member.findById(memberid)
				Project project = Project.findById(projectid)

				SubProject subproject

				Donate.withTransaction { donate_status ->
					Donate donate = Donate.findByOut_trade_no(out_trade_no)
					if(donate){
						render "success"
						return
					}
					
					//2.若是一起捐 则保存信息到subproject
					if(!subprojectid.equals("-1")){
						SubProject.withTransaction {subproject_status ->
							subproject = SubProject.findById(subprojectid)
							subproject.subrest -= Float.valueOf(donate_fee)
							subproject.subdonate += Float.valueOf(donate_fee)
							subproject.subprogress = 100-(subproject.subrest/subproject.subamount)*100
							//4.金额计算，subProject rest计算，
							if(subproject.subrest <= 0){
								//TODO
								subproject.subrest = 0
								subproject.subprogress = 100
							}
							subproject.save flush:true
						}
					}
					
					
					println "增加捐赠记录"
					long timestap = System.currentTimeMillis()/1000
					//捐赠信息
					donate = new Donate()
					donate.donateNo = UUID.randomUUID()
					donate.donateNoNew = project.id+""+member.id+""+timestap
					donate.money = Float.valueOf(total_fee)

					//记录支付金额信息
					donate.donate_fee = donate_fee
					donate.operate_fee = operate_fee
					donate.operate_fee_status = checked

					donate.date = new Date()
					donate.status = true
					donate.member = member
					donate.project = project
					//若是一起捐 保存捐赠信息到donate
					if(!subprojectid.equals("-1")) donate.subProject = subproject
					donate.out_trade_no = out_trade_no
					donate.openid = member?.openid
					donate.transaction_id = ""
					donate.attach = projectid+"#"+memberid+"#"+checked_string+"#"+donate_fee+"#"+operate_fee
					donate.type = "支付宝支付"
					donate.save flush:true

					donateurl = SCFIREConstants.PROJECT_DONATE_ELECTRONIC_INFO+donate?.id
					//donateurl = "http://www.huodui.org/scfire/user/modifyMoblie"
				}
				
				//微信发送模板支付凭证
				boolean proof = weiXinService.templet(WeiXinConstants.donate_id , member?.openid , donateurl , project?.name , Float.valueOf(total_fee)+"" , member?.nickname)
				//rest 减去donate_fee    不包含平台管理费
				project.rest -= Float.valueOf(donate_fee)
				project.progress = 100-(project.rest/project.amount)*100

				//将剩余的钱捐入某个永久项目
				if(project.rest <= 0){
					//TODO
					project.rest = 0
					project.progress = 100
					project.verified = SCFIREConstants.PROJECT_APPROVE_EXECUTE
					//保存系统通知消息
					SystemMessageService.sendSysMessage(SCFIREConstants.SYSTEM_MESSAGE_PROJECT_FUND_SUCCESS_FRONT+project.name+SCFIREConstants.SYSTEM_MESSAGE_PROJECT_FUND_SUCCESS_BACK, project.member)

					//筹款成功：推送该项目所有捐赠人，提示用户项目筹款成功，已进入执行阶段，点击详情持续关注项目进展
					Map<String, String> donateUsersOpenid = new HashMap<String, String>()
					Date  date = new Date();
					DateFormat fmt =new SimpleDateFormat("yyyy-MM-dd HH:mm");
					Iterator its = project?.donates?.iterator()
					while(its.hasNext()){
						Donate temp = (Donate)its.next()
						if(temp?.member?.openid){
							donateUsersOpenid.put(temp?.member?.openid , temp?.member?.openid)
						}
					}

					weiXinService.sendMassTemplateStatus(WeiXinConstants.service_id, donateUsersOpenid, project?.name+"项目已筹满，您支持的此项目已筹满，我们将尽快支付善款给项目发起人，点击详情持续关注项目最新进展。", fmt.format(date), "项目筹款", "筹款", "成功" , WeiXinConstants.server+"/project/projectDetail?projectid="+project?.id)
					
					//筹款成功：推送该项目发起人，提示用户项目筹款成功，会在5个工作日内打款到您的账上，请点击详情确认收款信息是否准确
					if(project?.member?.openid){
						weiXinService.template_status(WeiXinConstants.service_id, project?.member?.openid, project?.name+"项目已筹满，我们会在5个工作日内支付善款到您的银行卡上，点击详情查看并确认收款银行账号是否准确。", fmt.format(date), "项目筹款", "筹款", "成功" , WeiXinConstants.server+"/user/userAuthInfo")
					}

					//筹款成功：发布项目动态，“项目筹款成功”
					feedBackService.insertFeedBack(SCFIREConstants.PROJECT_FEEDBACK_FINISH, project.id+"")

				}
				//捐赠用户去重
				Set donateMember = new HashSet<>()
				 donateMember.add(member.id)
				 for(Donate d:project.donates){
				 def m = d.member.id
				 donateMember.add(m)
				 }
				//捐赠的用户数累加，按照捐一次累积一次，不做member的去重
				project.donateNum = project.donateNum+1
				project.save flush:true

			}//project.withTransaction }
			render "success"	//请不要修改或删除
			return


			//////////////////////////////////////////////////////////////////////////////////////////
		}else{//验证失败
			println "验证失败"
			render "fail"
			return
		}
	}*/
	
	/**
	 * 支付宝回调函数  权限放开 --- 紧急优化解决事务问题
	 */
	def alipayNotify(){
		println "支付宝回调.."
		String donateurl = "";
		Map<String,String> param = new HashMap<String,String>()
		Map requestParams = request.getParameterMap()
		for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
			String name = (String) iter.next()
			String[] values = (String[]) requestParams.get(name);
			String valueStr = ""
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == values.length - 1) ? valueStr + values[i]
						: valueStr + values[i] + ","
			}
			//乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
			//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
			param.put(name, valueStr)
			//			println name+":"+valueStr
		}

		//获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以下仅供参考)//
		//商户订单号
		String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
		//支付宝交易号
		String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8");
		//交易状态
		String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");

		println "交易状态："+trade_status

		String memberid = new String(request.getParameter("memberid").getBytes("ISO-8859-1"),"UTF-8");
		String projectid = new String(request.getParameter("projectid").getBytes("ISO-8859-1"),"UTF-8");
		String subprojectid = new String(request.getParameter("subprojectid").getBytes("ISO-8859-1"),"UTF-8");
		String total_fee = new String(request.getParameter("total_fee").getBytes("ISO-8859-1"),"UTF-8");
		boolean checked;
		String checked_string = new String(request.getParameter("checked").getBytes("ISO-8859-1"),"UTF-8").toLowerCase();
		float donate_fee = Float.parseFloat(new String(request.getParameter("donate_fee").getBytes("ISO-8859-1"),"UTF-8"));
		float operate_fee = Float.parseFloat(new String(request.getParameter("operate_fee").getBytes("ISO-8859-1"),"UTF-8"));

		if(checked_string.equals("true")){
			checked = true
		}else{
			checked = false
		}

		param.remove("memberid")
		param.remove("projectid")
		param.remove("checked")
		param.remove("donate_fee")
		param.remove("operate_fee")
		param.remove("subprojectid")
		//获取支付宝的通知返回参数，可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//

		if(AlipayNotify.verify(param)){//验证成功
			println "验证成功"

			boolean flag
			flag = payService.alipayCallBack(memberid, projectid, out_trade_no, out_trade_no, trade_status, subprojectid, total_fee, donate_fee, operate_fee, checked, checked_string)
			if(flag){
				render "success"	//请不要修改或删除
				return
			}else{
				render "fail"
				return
			}

			//////////////////////////////////////////////////////////////////////////////////////////
		}else{//验证失败
			println "验证失败"
			render "fail"
			return
		}
	}

	/**
	 * 页面微信付款成功回调函数
	 * @param total_fee
	 * @return total_fee
	 *
	 * **//*
	 def callBackPay(){
	 //获取用户基本信息
	 def user = springSecurityService.getCurrentUser()
	 def roles = springSecurityService.getAuthentication()?.authorities
	 //捐赠者
	 Member member = (Member)user
	 println "微信付款回调函数返回内容："+params
	 String total_fee = params.total_fee
	 String projectid = params.projectid
	 //捐赠电子证书地址
	 String donateurl = ""
	 try{
	 Project project = Project.findById(projectid)
	 if (project == null) {
	 notFound()
	 return
	 }
	 //捐赠信息
	 Donate donate = new Donate()
	 donate.donateNo = UUID.randomUUID()
	 donate.money = Float.valueOf(total_fee)
	 donate.date = new Date()
	 donate.status = true
	 donate.member = member
	 donate.project = project
	 donate.save flush:true
	 //donate.insert(failOnError: true)
	 donateurl = SCFIREConstants.PROJECT_DONATE_ELECTRONIC_INFO+donate.id
	 //这里有明显的计算问题，平台管理费并不知道有没有包含在totalfee里面
	 project.rest -= donate.money;
	 project.progress = 100-(project.rest/project.amount)*100;
	 //将剩余的钱捐入某个永久项目
	 if(project.rest < 0){
	 //TODO
	 project.rest = 0;
	 project.progress = 100;
	 //保存系统通知消息
	 SystemMessage systemMessage = new SystemMessage()
	 systemMessage.message = SCFIREConstants.SYSTEM_MESSAGE_PROJECT_FUND_SUCCESS_FRONT+project.name+SCFIREConstants.SYSTEM_MESSAGE_PROJECT_FUND_SUCCESS_BACK
	 systemMessage.date = new Date()
	 systemMessage.member = member
	 systemMessage.save flush:true
	 }
	 //捐赠的用户去重
	 Set donateMember = new HashSet<>()
	 donateMember.add(member.id)
	 for(Donate d:project.donates){
	 def m = d.member.id
	 donateMember.add(m)
	 }
	 project.donateNum = donateMember.size();
	 project.save (failOnError: true, flush:true)
	 //微信发送模板支付凭证
	 boolean proof = weiXinService.templet(WeiXinConstants.donate_id , member.openid , donateurl , project.name , total_fee , member.nickname)
	 }catch(Exception e){
	 LOG.error("save donate catch exception. "+e.getMessage());
	 }
	 }*/

	/**
	 * 微信付款成功回调函数
	 * @param null
	 * @return null
	 *
	 * **/
	/*def callBack(){
		response.setContentType("text/xml;charset=UTF-8")
		String response_ok_xml = "<xml>"+
				"<return_code>SUCCESS</return_code>"+
				"<return_msg>OK</return_msg>"+
				"</xml>"
		String response_fail_xml = "<xml>"+
				"<return_code>FAIL</return_code>"+
				"<return_msg>CANCEL</return_msg>"+
				"</xml>"

		//		try{
		String body = ""
		BufferedReader i = request.getReader()
		String line
		while ((line = i.readLine()) != null)
		{
			body += line
		}
		String attach = WeiXinUtil.getValue(body , "attach")
		String projectId = attach.split("#")[0]
		String memberId = attach.split("#")[1]
		boolean checked
		if(attach.split("#")[2].toLowerCase().equals("true")){
			checked = true
		}else{
			checked = false
		}


		def donate_fee = attach.split("#")[3] as float
		def operate_fee = attach.split("#")[4] as float
		def subprojectid = attach.split("#")[5]



		String total_fee = WeiXinUtil.getValue(body , "total_fee")
		String result_code = WeiXinUtil.getValue(body , "result_code")

		String out_trade_no = WeiXinUtil.getValue(body , "out_trade_no")
		String openid = WeiXinUtil.getValue(body , "openid")
		String transaction_id = WeiXinUtil.getValue(body , "transaction_id")


		if(result_code == "SUCCESS"){


			Project.withTransaction { project_status ->

				Member member = Member.findById(memberId)
				Project project = Project.findById(projectId)
				String donateurl = ""
				SubProject subproject

				

				Donate.withTransaction { donate_status ->
					Donate donate = Donate.findByOut_trade_no(out_trade_no)
					if(donate){
						response.getWriter().write(response_ok_xml)
						response.flushBuffer()
						return
					}
					
					//若是一起捐 则保存信息到subproject
					if(!subprojectid.equals("-1")){
						SubProject.withTransaction {subproject_status ->
							subproject = SubProject.findById(subprojectid)
							subproject.subrest -= Float.valueOf(donate_fee)
							subproject.subdonate += Float.valueOf(donate_fee)
							subproject.subprogress = 100-(subproject.subrest/subproject.subamount)*100
							//4.金额计算，subProject rest计算，
							if(subproject.subrest <= 0){
								//TODO
								subproject.subrest = 0
								subproject.subprogress = 100
							}
							subproject.save flush:true
						}
					}
					
					long timestap = System.currentTimeMillis()/1000

					//捐赠信息
					donate = new Donate()
					donate.donateNo = UUID.randomUUID()
					donate.donateNoNew = project.id+""+member.id+""+timestap
					donate.money = Float.valueOf(total_fee)/100

					donate.donate_fee = donate_fee
					donate.operate_fee = operate_fee
					donate.operate_fee_status = checked

					donate.date = new Date()
					donate.status = true
					donate.member = member
					donate.project = project
					//若是一起捐 保存捐赠信息到donate
					if(!subprojectid.equals("-1")) donate.subProject = subproject
					donate.out_trade_no = out_trade_no
					donate.openid = openid
					donate.transaction_id = transaction_id
					donate.attach = attach
					donate.type = "微信支付"
					donate.save flush:true

					donateurl = SCFIREConstants.PROJECT_DONATE_ELECTRONIC_INFO+donate.id
					//donateurl = "http://www.huodui.org/scfire/user/modifyMoblie"
				}
							
				//微信发送模板支付凭证
				boolean proof = weiXinService.templet(WeiXinConstants.donate_id , member?.openid , donateurl , project?.name , Float.valueOf(total_fee)/100+"" , member?.nickname)
				println "send stats : "+ proof
				//rest修改为donate_fee  不包含平台管理费
				project.rest -= Float.valueOf(donate_fee)
				project.progress = 100-(project.rest/project.amount)*100

				//将剩余的钱捐入某个永久项目
				if(project.rest <= 0){
					//TODO
					project.rest = 0
					project.progress = 100
					project.verified = SCFIREConstants.PROJECT_APPROVE_EXECUTE
					//保存系统通知消息
					SystemMessageService.sendSysMessage(SCFIREConstants.SYSTEM_MESSAGE_PROJECT_FUND_SUCCESS_FRONT+project.name+SCFIREConstants.SYSTEM_MESSAGE_PROJECT_FUND_SUCCESS_BACK, project.member);

					//筹款成功：推送该项目所有捐赠人，提示用户项目筹款成功，已进入执行阶段，点击详情持续关注项目进展
					Map<String, String> donateUsersOpenid = new HashMap<String, String>()
					Date  date = new Date();
					DateFormat fmt =new SimpleDateFormat("yyyy-MM-dd HH:mm");
					Iterator its = project?.donates?.iterator()
					while(its.hasNext()){
						Donate temp = (Donate)its.next()
						if(temp?.member?.openid){
							donateUsersOpenid.put(temp?.member?.openid , temp?.member?.openid)
						}
					}
					weiXinService.sendMassTemplateStatus(WeiXinConstants.service_id, donateUsersOpenid, project?.name+"项目已筹满，您支持的此项目已筹满，我们将尽快支付善款给项目发起人，点击详情持续关注项目最新进展。", fmt.format(date), "项目筹款", "筹款", "成功" , WeiXinConstants.server+"/project/projectDetail?projectid="+project?.id)



					//筹款成功：推送该项目发起人，提示用户项目筹款成功，会在5个工作日内打款到您的账上，请点击详情确认收款信息是否准确
					if(project?.member?.openid){
						weiXinService.template_status(WeiXinConstants.service_id, project?.member?.openid, project?.name+"项目已筹满，我们会在5个工作日内支付善款到您的银行卡上，点击详情查看并确认收款银行账号是否准确。", fmt.format(date), "项目筹款", "筹款", "成功" , WeiXinConstants.server+"/user/userAuthInfo")
					}
					
					//筹款成功：发布项目动态，“项目筹款成功”
					feedBackService.insertFeedBack(SCFIREConstants.PROJECT_FEEDBACK_PASS_F+project.name+SCFIREConstants.PROJECT_FEEDBACK_PASS_E, project.id+"")
				}

				//捐赠的用户去重
				 Set donateMember = new HashSet<>()
				 donateMember.add(member.id)
				 for(Donate d:project.donates){
				 def m = d.member.id
				 donateMember.add(m)
				 }
				 project.donateNum = donateMember.size()
				//捐赠的用户数累加，按照捐一次累积一次，不做member的去重
				project.donateNum = project.donateNum+1
				project.save flush:true

			}//project.withTransaction }


			response.getWriter().write(response_ok_xml)
			response.flushBuffer()
			return


		}

		//		}catch(Exception e){
		//			println "回调接口出错"
		//			println e
		//
		//		}
	}*/
	
	/**
	 * 微信付款成功回调函数  --- 紧急优化解决事务问题
	 * @param null
	 * @return null
	 *
	 * **/
	def callBack(){
		response.setContentType("text/xml;charset=UTF-8")
		String response_ok_xml = "<xml>"+
				"<return_code>SUCCESS</return_code>"+
				"<return_msg>OK</return_msg>"+
				"</xml>"
		String response_fail_xml = "<xml>"+
				"<return_code>FAIL</return_code>"+
				"<return_msg>CANCEL</return_msg>"+
				"</xml>"

		//		try{
		String body = ""
		BufferedReader i = request.getReader()
		String line
		while ((line = i.readLine()) != null)
		{
			body += line
		}
		
//				String attach = projectid +"#"+member.id+"#"+checked+"#"+donate_fee+"#"+operate_fee+"#"+subprojectid
//				String attach =     "{\"projectid\":\""+projectid+"\",\"memberid\":\""+member.id+"\","+
//				"\"checked\":\""+checked+"\",\"donate_fee\":\""+donate_fee+"\","+
//				"\"operate_fee\":\""+operate_fee+"\",\"subprojectid\":\""+subprojectid+"\",\"donateNoNew\":\""+donateNoNew+"\"}";
		
//		String attach =     "{\"p\":\""+projectid+"\",\"m\":\""+member.id+"\","+
//		"\"c\":\""+checked+"\",\"df\":\""+donate_fee+"\","+
//		"\"of\":\""+operate_fee+"\",\"s\":\""+subprojectid+"\",\"dn\":\""+donateNoNew+"\"}";
		
		
		String attach = WeiXinUtil.getValue(body , "attach")
		def attachJSON = JSONObject.fromObject(attach)
		String projectId = attachJSON.p
		String memberId = attachJSON.m
		boolean checked
		if("true".equalsIgnoreCase(attachJSON.c)){
			checked = true
		}else{
			checked = false
		}
		def donate_fee = attachJSON.df as float
		def operate_fee = attachJSON.of as float
		def subprojectid = attachJSON.s
		def donateNoNew = attachJSON.dn
		
//		String projectId = attach.split("#")[0]
//		String memberId = attach.split("#")[1]
//		boolean checked
//		if(attach.split("#")[2].toLowerCase().equals("true")){
//			checked = true
//		}else{
//			checked = false
//		}
//		def donate_fee = attach.split("#")[3] as float
//		def operate_fee = attach.split("#")[4] as float
//		def subprojectid = attach.split("#")[5]



		String total_fee = WeiXinUtil.getValue(body , "total_fee")
		String result_code = WeiXinUtil.getValue(body , "result_code")

		String out_trade_no = WeiXinUtil.getValue(body , "out_trade_no")
		String openid = WeiXinUtil.getValue(body , "openid")
		String transaction_id = WeiXinUtil.getValue(body , "transaction_id")


		if(result_code == "SUCCESS"){
			
			boolean flag
			flag = payService.weixinCallBack(memberId, projectId, donate_fee, operate_fee, subprojectid, total_fee, out_trade_no, openid, transaction_id, checked, attach,donateNoNew)
			
			if(flag){
				response.getWriter().write(response_ok_xml)
				response.flushBuffer()
			}else{
				response.getWriter().write(response_fail_xml)
				response.flushBuffer()
			}
		}
		
		
	}

	
	/**
	 * 捐赠完成后跳到这个页面
	 *
	 * @return
	 */
	def donateFinish() {
		render view:"payfinish"
	}
	
	/**
	 * 将获取最近用户的一笔捐赠
	 * 
	 * @return
	 */
	def donateElectronicInfo() {
		def format = request.getHeader("format")
		def userAgent = request.getHeader("User-Agent")
		//获取用户基本信息
		def user = springSecurityService.getCurrentUser()
		Member member = (Member)user
				
		//如果有则跳转到电子证书页面，否则返回等待页面
		if(member?.donates?.first() != null){
			redirect(controller:"donate" ,action: "donateElectronicInfo", params:[donateid: member.donates.first().id])
			return
		}
		else{
			render view:"waiting",model:[member:member]
			return
		}
		render view:"waiting",model:[member:member]
	}
	
	/**
	 * 将获取最近用户的一笔捐赠----静态页面
	 *
	 * @return
	 */
	def donateElectronicInfo2() {
		def format = request.getHeader("format")
		def userAgent = request.getHeader("User-Agent")
		//获取用户基本信息
		def user = springSecurityService.getCurrentUser()
		Member member = (Member)user
		
		
		//这里把参数传进去		
		redirect(controller:"donate" ,action: "donateElectronicInfo2", params:[])
	}
	/**
	 * 项目信息未找到
	 * @param null
	 * @return null
	 *
	 * **/
	protected void notFound() {
		def gson = new Gson()
		withFormat {
			html {
				flash.message = "捐赠项目未找到！"
				redirect (controller: "errors", action: "notFound")
			}
			json {
				gson.setResult(false)
				gson.setCode(404)
				gson.setInfo(["text": "未找到该项目！"])
				render gson as JSON
			}
		}
	}
	
	/**
	 * 重新计算项目捐赠信息
	 * @return
	 */
	def renewProject(){
		List<Project> projects = Project.findAllByVerifiedInList(["pass" , "expired"])
		for(def project : projects){
			
			List<Donate> donates = Donate.findAllByProject(project);
			float sum = 0;
			for(def donate : donates){
				sum += donate.donate_fee
			}
			
			println project.name +"    项目显示捐赠额："+(project.amount - project.rest) +"     实际捐赠数："+sum+"     "+project.verified
			
			project.rest = project.amount - sum
			if(project.rest < 0){
				project.rest = 0
			}
			
			project.progress = 100-(project.rest/project.amount)*100
			
			//project.save(flush : true)
			
			//println project.name +"    项目显示捐赠额："+(project.amount - project.rest) +"     实际捐赠数："+sum+"     "+project.verified
			
			
			render "sucess"
			
			//render project.name +"    项目总额："+(project.amount - project.rest) +"     实际金额："+sum+"     "+project.verified +"<br/>"
			
			
			
		}
		
		return
		
		
	}
	
	/**
	 * 重新计算一起捐
	 */
	def renewSubProject(){
		List<Project> projects = Project.findAllByVerifiedInList(["pass" , "expired"])
		for(def project : projects){
			List<SubProject> subprojects = SubProject.findAllByProject(project);
			for(def subproject : subprojects){
				//-1标识无限量， 暂时不知道逻辑，没做处理
				if(subproject.subamount == -1){
					continue;
				}
				List<Donate> donates = Donate.findAllBySubProject(subproject);
				float sum = 0;
				for(def donate : donates){
					sum += donate.donate_fee
				}
				//剩余 = 总量 - 实际总和
				
				println project.name +"    项目显示捐赠额："+(subproject.subamount - subproject.subrest) +"     实际捐赠数："+sum+"     "+project.verified +"<br/>"
				
				subproject.subrest = subproject.subamount - sum
				if(subproject.subrest < 0){
					subproject.subrest = 0
				}
			//	subproject.save(flush : true)
				
				render "success"
				//render project.name +"    数据库记录总额："+(subproject.subamount - subproject.subrest) +"     实际金额："+sum+"     "+project.verified +"<br/>"
				
			}
		}
		return;
	}
	
	
	
	
	
	
	//手机号、Unionid、昵称、头像URL、捐赠流水号、捐赠金额、捐赠时间、捐赠项目
	
	
	def SaveDonateByOther(){	
		println new Date().getTime()
		JSONObject jsons = new JSONObject()
		def requestJSON = request.JSON;
		def member
		def project
		boolean flag2 =true;
		println requestJSON
		println requestJSON.public_key
		def interfaceMesage = InterfaceMesage.findByPublic_key(requestJSON.public_key)
		if(interfaceMesage?.flag==true){
			String mobile= requestJSON.mobile
			String unionid= requestJSON.unionid
			String nickname= requestJSON.nickname
			String headimgurl= requestJSON.headimgurl
			String out_trade_no= requestJSON.out_trade_no
			String money= requestJSON.money
			String date= requestJSON.date
			String projects= requestJSON.project
			println projects
			
			if(mobile==null ||unionid==null||nickname==null||headimgurl==null||out_trade_no==null||money==null||date==null||projects==null){
				jsons.put("code", -2);
				jsons.put("errMsg", "Parameters Illegal");
				flag2=false;
				
			}else  if(mobile=="" ||unionid==""||nickname==""||headimgurl==""||out_trade_no==""||money==""||date==""||projects==""){
				jsons.put("code", -2);
				jsons.put("errMsg", "Parameters Illegal");
				flag2=false;
			}else{
				String projectid = requestJSON.project
				project = Project.findById(Long.valueOf(projectid))
				if(!project){
					jsons.put("code", -21);
					jsons.put("errMsg", "project Illegal");
					flag2=false;
				}
				SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			       try {
			           format.setLenient(false);
			           format.parse(date);
			        } catch (ParseException e) {
					jsons.put("code", -22);
					jsons.put("errMsg", "date Illegal");
		               flag2=false;
		           }
				try {
					Float.valueOf(money)
				} catch (Exception e) {
				jsons.put("code", -23);
				jsons.put("errMsg", "money Illegal");
				   flag2=false;
				}
				
			}
			
			
			if(flag2){
				HashMap<String,String> toSign = new HashMap<String,String>();
				toSign.put("mobile",requestJSON.mobile);
				toSign.put("unionid", requestJSON.unionid);
				toSign.put("nickname", requestJSON.nickname);
				toSign.put("headimgurl", requestJSON.headimgurl);
				toSign.put("out_trade_no", requestJSON.out_trade_no);
				toSign.put("money", requestJSON.money);
				toSign.put("date", requestJSON.date);
				toSign.put("project", requestJSON.project);
				toSign.put("public_key", interfaceMesage.public_key);
		   String sign = SIGN.getSignature(toSign, interfaceMesage.sercurity_key);
		   String checkSign = requestJSON.sign
		   if(sign==checkSign){
			   member= Member.findByOtherUnionidAndEnabled(requestJSON.unionid,true);
				   if(member==null){
					   member= Member.findByMobile(requestJSON.mobile);
					   if(member==null){
						   member = new Member();
						   member.otherUnionid = requestJSON.unionid;
						   member.mobile = requestJSON.mobile;
						   member.nickname = requestJSON.nickname;
						   member.headimgurl = requestJSON.headimgurl;
						   member.username = UUID.randomUUID().toString().replaceAll("-", "").toString()
						   member.password = "csstsari"
						   member.enabled = true
						   member.accountExpired = false
						   member.accountLocked = false
						   member.passwordExpired = false
						   member.save(flush:true)
						   if(!member.save()){
							   member.errors.allErrors.each{
								   println(it)
							   }
						   }
						   Authority authority = Authority.findByAuthority("ROLE_USER")
						   def memberAuthority = MemberAuthority.get(member?.id,authority.id)
						   if(!memberAuthority){
							   MemberAuthority.create(member , authority , true)
						   }
					   }else{
						   member.otherUnionid = requestJSON.unionid;
						   member.save(flush:true)
					   }
					   
				   }else{
					   if(member.moblie!= requestJSON.moblie){
						   member.moblie = requestJSON.moblie
						   member.save(flush:true)
						   if(!member.save()){
							   member.errors.allErrors.each{
								   println(it)
							   }
						   }
					   }
				   }
				   
			   
			   long timestap = System.currentTimeMillis()/1000
			   String donateNoNew = project.id+""+member.id+""+timestap
			   String openid=requestJSON.unionid
			   String total_fee=requestJSON.money
			   float donate_fee=Float.valueOf(total_fee);
			   float operate_fee=0
			   String transaction_id = requestJSON.out_trade_no
			   String attach =     "{\"p\":\""+project.id+"\",\"m\":\""+member.id+"\","+
			   "\"c\":\""+"false"+"\",\"df\":\""+requestJSON.money+"\","+
			   "\"of\":\""+"0"+"\",\"s\":\""+"-1"+"\",\"dn\":\""+donateNoNew+"\"}";
//				/(java.lang.Long, java.lang.Long, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.Boolean, java.lang.String, java.lang.String, java.lang.String)
			   
			   Map<String,Object> map = new HashMap<String,Object>();
			   map.put("memberid",member.id+"");
			   map.put("projectid",project.id+"");
			   map.put("donate_fee",donate_fee+"");
			   map.put("operate_fee",operate_fee+"");
			   map.put("subproject","-1");
			   map.put("total_fee",total_fee);
			   map.put("out_trade_no",out_trade_no);
			   map.put("openid",openid);
			   map.put("transaction_id",transaction_id);
			   map.put("checked",false);
			   map.put("attach",attach);
			   map.put("donateNoNew",donateNoNew);
			   map.put("type","米其林");
			   //produce(map);
			   boolean flag = payService.checkCallBack(member.id+"", project.id+"", donate_fee, operate_fee, "-1", total_fee, out_trade_no, openid, transaction_id, false, attach,donateNoNew,"米其林",requestJSON.date)
			   if(flag==true){
				   jsons.put("code", 0)
				   jsons.put("errMsg", "")
			   }else{
			   jsons.put("code", -4);
			   jsons.put("errMsg", "system error");
			   }
			   
			   
		   }else{
			   jsons.put("code", -2)
			   jsons.put("errMsg", "Parameters are modified")
		   }
			}	
		}else{
			jsons.put("code", -1)
			jsons.put("errMsg", "key is expired ")
		}
		println new Date().getTime()
			withFormat {
				json {
					render jsons as JSON
				}
			}
	}
	
	
	
	
	public  void produce(Map map) {
            while(true){
                synchronized (queue) {
                    while(queue.size() == queueSize){
                        try {
                            System.out.println("队列满，等待有空余空间");
                            queue.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                            queue.notify();
                        }
                    }
                    queue.offer(map);        //每次插入一个元素
                    queue.notify();
                    System.out.println("向队列取中插入一个元素，队列剩余空间："+(queueSize-queue.size()));
                }
            }
        }
	
	public  void consume() {
		while(true){
			synchronized (queue) {
				while(queue.size() == 0){
					try {
						System.out.println("队列空，等待数据");
						queue.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
						queue.notify();
					}
				}
				queue.poll();          //每次移走队首元素
				queue.notify();
				System.out.println("从队列取走一个元素，队列剩余"+queue.size()+"个元素");
			}
		}
	}
	
	
	
	
	
	
	
	
	
	
}
